package com.lottery.im.base;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.StringRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.widget.FrameLayout;
import butterknife.ButterKnife;
import com.lottery.im.util.AppManagerUtil;
import com.lottery.im.util.Density;
import com.lottery.im.util.StatusBarHelper;
import com.lottery.im.util.ToastUtils;
import com.lottery.im.util.WindowInsetLayout;
import com.lottery.im.widget.dialog.LoadingDialogUtil;
import com.trello.rxlifecycle2.components.support.RxAppCompatActivity;
import java.lang.reflect.Field;

/**
 * the container activity for {@link BaseSwipeFragment}.
 * Created by cgspine on 15/9/14.
 */
public abstract class BaseFragmentActivity<T extends BaseActivityPresenter>
    extends RxAppCompatActivity {
  private static final String TAG = "BaseFragmentActivity";
  private WindowInsetLayout mFragmentContainer;

  @SuppressWarnings("SameReturnValue")
  protected abstract int getContextViewId();

  protected T presenter;
  protected Context mContext;
  protected Activity mActivity;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    StatusBarHelper.translucent(this);
    StatusBarHelper.setStatusBarDarkMode(this);
    Density.setCustomDensity(this, getApplication());
    doBeforeSetcontentView();
    mFragmentContainer = new WindowInsetLayout(this);
    mFragmentContainer.setId(getContextViewId());
    setContentView(mFragmentContainer);
    ButterKnife.bind(mFragmentContainer);
    mContext = this.getApplicationContext();
    mActivity = this;
    initPresenter();
  }

  /**
   * 设置layout前配置
   */
  protected void doBeforeSetcontentView() {
    // 把actvity放到application栈中管理
    AppManagerUtil.getAppManager().addActivity(this);
  }

  public FrameLayout getFragmentContainer() {
    return mFragmentContainer;
  }

  protected abstract void initPresenter();

  @Override
  public void onBackPressed() {
    BaseSwipeFragment fragment = getCurrentFragment();
    if (fragment != null) {
      fragment.popBackStack();
    }
  }

  /**
   * get the current Fragment.
   */
  public BaseSwipeFragment getCurrentFragment() {
    return (BaseSwipeFragment) getSupportFragmentManager().findFragmentById(getContextViewId());
  }

  /**
   * start a new fragment and then destroy current fragment.
   * assume there is a fragment stack(A->B->C), and you use this method to start a new
   * fragment D and destroy fragment C. Now you are in fragment D, if you want call
   * {@link #popBackStack()} to back to B, what the animation should be? Sometimes we hope run
   * animation generated by transition B->C, but sometimes we hope run animation generated by
   * transition C->D. this why second parameter exists.
   *
   * @param fragment new fragment to start
   * @param useNewTransitionConfigWhenPop if true, use animation generated by transition C->D,
   * else, use animation generated by transition B->C
   */
  public int startFragmentAndDestroyCurrent(final BaseSwipeFragment fragment,
      final boolean useNewTransitionConfigWhenPop) {
    final BaseSwipeFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
    String tagName = fragment.getClass().getSimpleName();
    FragmentManager fragmentManager = getSupportFragmentManager();
    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction()
        .setCustomAnimations(transitionConfig.enter, transitionConfig.exit,
            transitionConfig.popenter, transitionConfig.popout)
        .replace(getContextViewId(), fragment, tagName);
    int index = transaction.commit();
    Utils.findAndModifyOpInBackStackRecord(fragmentManager, -1, new Utils.OpHandler() {
      @Override
      public boolean handle(Object op) {
        Field cmdField = null;
        try {
          cmdField = op.getClass().getDeclaredField("cmd");
          cmdField.setAccessible(true);
          int cmd = (int) cmdField.get(op);
          if (cmd == 1) {
            if (useNewTransitionConfigWhenPop) {
              Field popEnterAnimField = op.getClass().getDeclaredField("popEnterAnim");
              popEnterAnimField.setAccessible(true);
              popEnterAnimField.set(op, transitionConfig.popenter);

              Field popExitAnimField = op.getClass().getDeclaredField("popExitAnim");
              popExitAnimField.setAccessible(true);
              popExitAnimField.set(op, transitionConfig.popout);
            }

            Field oldFragmentField = op.getClass().getDeclaredField("fragment");
            oldFragmentField.setAccessible(true);
            Object fragmentObj = oldFragmentField.get(op);
            oldFragmentField.set(op, fragment);
            Field backStackNestField = Fragment.class.getDeclaredField("mBackStackNesting");
            backStackNestField.setAccessible(true);
            int oldFragmentBackStackNest = (int) backStackNestField.get(fragmentObj);
            backStackNestField.set(fragment, oldFragmentBackStackNest);
            backStackNestField.set(fragmentObj, --oldFragmentBackStackNest);
            return true;
          }
        } catch (NoSuchFieldException e) {
          e.printStackTrace();
        } catch (IllegalAccessException e) {
          e.printStackTrace();
        }
        return false;
      }
    });
    return index;
  }

  public int startFragment(BaseSwipeFragment fragment) {
    Log.i(TAG, "startFragment");
    BaseSwipeFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
    String tagName = fragment.getClass().getSimpleName();
    return getSupportFragmentManager()
        .beginTransaction()
        .setCustomAnimations(transitionConfig.enter, transitionConfig.exit,
            transitionConfig.popenter, transitionConfig.popout)
        .replace(getContextViewId(), fragment, tagName)
        .addToBackStack(tagName)
        .commit();
  }

  /**
   * 退出当前的 Fragment。
   */
  public void popBackStack() {
    Log.i(TAG, "popBackStack: getSupportFragmentManager().getBackStackEntryCount() = "
        + getSupportFragmentManager().getBackStackEntryCount());
    if (getSupportFragmentManager().getBackStackEntryCount() <= 1) {
      BaseSwipeFragment fragment = getCurrentFragment();
      if (fragment == null) {
        finish();
        return;
      }
      BaseSwipeFragment.TransitionConfig transitionConfig = fragment.onFetchTransitionConfig();
      Object toExec = fragment.onLastFragmentFinish();
      if (toExec != null) {
        if (toExec instanceof BaseSwipeFragment) {
          BaseSwipeFragment mFragment = (BaseSwipeFragment) toExec;
          startFragment(mFragment);
        } else if (toExec instanceof Intent) {
          Intent intent = (Intent) toExec;
          finish();
          startActivity(intent);
          overridePendingTransition(transitionConfig.popenter, transitionConfig.popout);
        } else {
          throw new Error("can not handle the result in onLastFragmentFinish");
        }
      } else {
        finish();
        overridePendingTransition(transitionConfig.popenter, transitionConfig.popout);
      }
    } else {
      getSupportFragmentManager().popBackStackImmediate();
    }
  }

  /**
   * <pre>
   * 返回到clazz类型的Fragment，
   * 如 Home --> List --> Detail，
   * popBackStack(Home.class)之后，就是Home
   *
   * 如果堆栈没有clazz或者就是当前的clazz（如上例的popBackStack(Detail.class)），就相当于popBackStack()
   * </pre>
   */
  public void popBackStack(Class<? extends BaseSwipeFragment> clazz) {
    getSupportFragmentManager().popBackStack(clazz.getSimpleName(), 0);
  }

  /**
   * <pre>
   * 返回到非clazz类型的Fragment
   *
   * 如果上一个是目标clazz，则会继续pop，直到上一个不是clazz。
   * </pre>
   */
  public void popBackStackInclusive(Class<? extends BaseSwipeFragment> clazz) {
    getSupportFragmentManager().popBackStack(clazz.getSimpleName(),
        FragmentManager.POP_BACK_STACK_INCLUSIVE);
  }

  public void showError() {
    ToastUtils.showToast(this, "网络异常,建议检查下网络～");
  }

  public void showToast(String msg) {
    ToastUtils.showToast(this, msg);
  }

  public void showToast(@StringRes int res) {
    ToastUtils.showToast(this, mActivity.getResources().getString(res));
  }

  public void showLoadingDialog() {
    LoadingDialogUtil.showProgressDialog(this);
  }

  public void cancelLoadingDialog() {
    LoadingDialogUtil.cancelProgressDialog();
  }

  @Override
  protected void onDestroy() {
    super.onDestroy();
    ButterKnife.bind(this).unbind();
    AppManagerUtil.getAppManager().finishActivity(this);
  }
}